home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 17 / CU Amiga Magazine's Super CD-ROM 17 (1997)(EMAP Images)(GB)[!][issue 1997-12].iso / CUCD / Programming / DiceSource / src / vmake / Command.c next >
Encoding:
C/C++ Source or Header  |  1997-09-09  |  51.6 KB  |  1,497 lines

  1. /*
  2.  *    (c)Copyright 1992-1997 Obvious Implementations Corp.  Redistribution and
  3.  *    use is allowed under the terms of the DICE-LICENSE FILE,
  4.  *    DICE-LICENSE.TXT.
  5.  */
  6. #include "vmake.h"
  7.  
  8. Prototype int build_command(char *buf, int len, char *template, char *sel);
  9. Prototype void do_command(char *string);
  10. Prototype int save_current(int perm);
  11. Prototype void reset_options(void);
  12. Prototype int set_option(struct G_OBJECT *object,char **argv);
  13. Prototype void exec_command(char *cmd, char *sel);
  14. Prototype void set_workdir(void);
  15.  
  16. void unload_symbols(void);
  17. void load_symbols(void);
  18. void add_list(struct G_LIST *list, char *name, int private);
  19. void add_listitem(struct G_LIST *list, char *name, int private, int dirty);
  20.  
  21. #define MAX_SYMBOL 31
  22. #define LINE_LEN  78
  23. #define MIN_LINE  10
  24. #define SYM_PROJCFG "CFGNAME"
  25.  
  26. static int showcmd;
  27.  
  28. /***********************************************************************************
  29.  * Procedure: get_cursel
  30.  * Synopsis:  name = get_cursel();
  31.  * Purpose:   Return the name associated with the current selection
  32.  ***********************************************************************************/
  33. static char *get_cursel(void)
  34. {
  35.    struct G_OBJECT *object;
  36. #define object_list  ((struct G_LIST   *)object)
  37.  
  38.    /* We need to determine the currently selected file */
  39.    for(object = global.objects; object != NULL; object = object->next)
  40.    {
  41.       if ((object->class == CLASS_LIST) && object_list->sel)
  42.          return(object_list->sel->buf);
  43. #undef object_list
  44.    }
  45.    return("");
  46. }
  47.  
  48. /*****************************************************************************
  49.  * Procedure: GetPubScrName
  50.  * Synopsis:  bool = GetPubScrName(scr, buff)
  51.  * Purpose:   fill the name of public a screen int a buffer, return TRUE
  52.  *            if found
  53.  *****************************************************************************/
  54. int GetPubScrName( struct Screen * scr, UBYTE * namebuff )
  55. {
  56.    struct List        * scrlist;
  57.    struct Node        * node;
  58.  
  59.    namebuff[0] = 0;
  60.  
  61.    if (AslBase) /* need Dos 2.0 or higher for this trick */
  62.       if(scrlist = LockPubScreenList()) 
  63.       {
  64.          /* traverse the public screen node list looking for our screen */
  65.          for ( node = scrlist->lh_Head; node->ln_Succ; node = node->ln_Succ ) 
  66.          {
  67.             if ( ((struct PubScreenNode *)node)->psn_Screen == scr ) 
  68.             {
  69.                strcpy( namebuff, node->ln_Name );
  70.                break;
  71.             }
  72.          }
  73.  
  74.          UnlockPubScreenList();
  75.       }
  76.  
  77.    return( namebuff[0] ? TRUE : FALSE );
  78.  
  79. } // GetPubScrName()
  80.  
  81. /***********************************************************************************
  82.  * Procedure: build_command
  83.  * Synopsis:  rc = build_command(buf, len, template)
  84.  * Purpose:   Construct a command to be issued
  85.  *            The template may have % strings in it where we will substitute:
  86.  *               %s   - Current selection
  87.  *               %f   - The current DMAKEFILE
  88.  *               %o   - An optional selection
  89.  *               %t   - The object module version of a file
  90.  *               %r   - Relative pathname of file
  91.  *               %(x) - The expansion of symbol X
  92.  *               %%   - insert one literal % in the buffer
  93.  ***********************************************************************************/
  94. int build_command(char *buf, int len, char *template, char *sel)
  95. {
  96.    char *name;
  97.    int nlen;
  98.    int makeobj;
  99.    /* note: MAX_FILENAME is greater than MAXPBUBSCREENNAME */
  100.    char exname[MAX_FILENAME+1];
  101.  
  102.    while(*template && len)
  103.    {
  104.       if (*template != '%')
  105.       {
  106.          *buf++ = *template++;
  107.          len--;
  108.       }
  109.       else
  110.       {
  111.          int cvalid = 1; /* Assume valid substitution */
  112.          char req;
  113.          makeobj = 0;
  114.          req = toupper(template[1]);
  115.          template += 2; /* skip over %x */
  116.          name = sel;
  117.          switch(req)
  118.          {
  119.             case 'F':
  120.                {
  121.                   BPTR savelock = 0;
  122.                   if (global.homedir)
  123.                      savelock = CurrentDir(global.homedir);
  124.                   expand_filename(Sym_Lookup(SYM_SCRIPT), exname);
  125.                   name = exname;
  126.                   if (savelock)
  127.                      CurrentDir(savelock);
  128.                   break;
  129.                }
  130.             case '(':
  131.                {
  132.                   char symbol[MAX_SYMBOL+1];
  133.                   int i;
  134.                   i = 0;
  135.                   for(i = 0; *template && (*template != ')'); template++)
  136.                      if (i < MAX_SYMBOL) symbol[i++] = *template;
  137.                   symbol[i] = 0;
  138.                   name = Sym_Lookup(symbol);
  139.                   if (*template == ')') template++;
  140.                   if (!*name)
  141.                   {
  142.                      i = atoi(symbol);
  143.                      if ((i > 0) && (i <= NUM_CONFIG))
  144.                      {
  145.                         name = global.text[CONFIG_BASE-1+i];
  146.                         if (name == NULL) name = "";
  147.                         else
  148.                         {
  149.                            int rc;
  150.  
  151.                            /* We want to recurse to parse out any substitutions     */
  152.                            /* in the string.  Note that in order to prevent runaway */
  153.                            /* recursion, we temporarily kill the config string      */
  154.                            global.text[CONFIG_BASE-1+i] = "";
  155.                            rc = build_command(buf, len, name, sel);
  156.                            global.text[CONFIG_BASE-1+i] = name;
  157.  
  158.                            /* if something went wrong on the recursion, just get    */
  159.                            /* out of here.                                          */
  160.                            if (rc) return(i);
  161.  
  162.                            /* This is a little tricky, what we are doing is cheating*/
  163.                            /* by letting it fill in the buffer with what is already */
  164.                            /* there.  This is harmless (the copy is onto itself) and*/
  165.                            /* allows us to get the length checking done for free    */
  166.                            name = buf;
  167.                         }
  168.                      }
  169.                      else
  170.                      {
  171.                         int max, istart;
  172.                         switch (toupper(*symbol))
  173.                         {
  174.                         case 'T':
  175.                            max = NUM_TEXT;
  176.                            istart = 0;
  177.                            break;
  178.                         case 'C':
  179.                            max = NUM_CONFIG;
  180.                            istart = CONFIG_BASE;
  181.                            break;
  182.                         case 'S':
  183.                            max = NUM_SUBRTN;
  184.                            istart = SUBRTN_BASE;
  185.                            break;
  186.                         default:
  187.                            max = 0;
  188.                            break;
  189.                         }
  190.                         i = atoi(symbol+1);
  191.                         if ((i > 0) && (i <= max))
  192.                         {
  193.                            name = global.text[istart+i-1];
  194.                         }
  195.                      }
  196.                   }
  197.                }
  198.                break;
  199.  
  200.             case 'T':
  201.                {
  202.                   char *p;
  203.                   if (!*name)
  204.                   {
  205.                      p = Sym_Lookup("EXEDIR");
  206.                      name = Sym_Lookup("PROJECT");
  207.                   }
  208.                   else
  209.                   {
  210.                      p = Sym_Lookup("OD");
  211.                      makeobj = 1;
  212.                   }
  213.  
  214.                   /* we need to first copy over the output directory */
  215.                   nlen = strlen(p);
  216.                   if (nlen > len)
  217.                   {
  218.                      request(1, TEXT_BUFFOVFL, NULL, NULL);
  219.                      return(1);
  220.                   }
  221.                   strcpy(buf, p);
  222.                   buf += nlen;
  223.                   len -= nlen;
  224.                }
  225.                break;
  226.  
  227.             case 'N':
  228.                if (global.screen && GetPubScrName(global.screen, exname))
  229.                   name = exname;
  230.                else
  231.                   name = "Workbench";
  232.                break;
  233.  
  234.             case 'R':
  235.             case 'S':
  236.                /* If nothing is selected, and they required a selection, let  */
  237.                /* them know and abort the command                             */
  238.                if (!*sel)
  239.                {
  240.                   request(1, TEXT_NOSEL, NULL, NULL);
  241.                   return(1);
  242.                }
  243.  
  244.                /* Expand pathname for 'S', not for 'R' */
  245.                if (req == 'R') break;
  246.                /* Else fall through to prepend the path to the name */
  247.  
  248.             case 'O':
  249.                expand_filename(sel, exname);
  250.                name = exname;
  251.                break;
  252.             case '%':
  253.                /* interpret "%%" as just "%" and stuff it into the command    */
  254.                /* buffer.  Fall through to default processing for literals.   */
  255.                template += 1;
  256.             default:
  257.                cvalid = 0; /* just copy literally, not a substitution */
  258.          }
  259.          if (cvalid) /* Means we're doing a substitution */
  260.          {
  261.             /* name is what we want to fill the current buffer with */
  262.             nlen = strlen(name);
  263.             if (nlen > len)
  264.             {
  265.                request(1, TEXT_BUFFOVFL, NULL, NULL);
  266.                return(1);
  267.             }
  268.             strcpy(buf, name);
  269.             if (makeobj)
  270.             {
  271.                /* If they requested a output file, we need to convert the */
  272.                /* file to an object file name                             */
  273.                if (nlen > 2 && (buf[nlen-2] == '.'))
  274.                   buf[nlen-1] = 'o';
  275.             }
  276.             buf += nlen;
  277.             len -= nlen;
  278.          }
  279.          else /* Just copy over literally */
  280.          {
  281.             /* just do the '%' here, main loop checks length as well */
  282.             *buf++ = '%';
  283.             template -= 1;  /* back up to char after '%' */
  284.             len--;
  285.          }
  286.       }
  287.    }
  288.    *buf++ = 0;  /* Don't forget to null terminate the result */
  289.    return(0);
  290. }
  291.  
  292. /***********************************************************************************
  293.  * Procedure: parse_keyword
  294.  * Synopsis:  ptr = parse_keyword(str, buf);
  295.  * Purpose:   Parse a keyword into the buffer
  296.  ***********************************************************************************/
  297. char *parse_keyword(char *str, char *buf)
  298. {
  299.    int i;
  300.    /* Gather the string into a buffer */
  301.    i = 0;
  302.    while(*str == ' ') str++;
  303.  
  304.    while((*str) && (*str != ' '))
  305.    {
  306.       buf[i++] = *str++;
  307.       if (i > MAX_SYMBOL) return(str);
  308.    }
  309.    buf[i] = 0;
  310.    while(*str == ' ') str++;
  311.    return(str);
  312. }
  313.  
  314. /***********************************************************************************
  315.  * Procedure: exec_command
  316.  * Synopsis:  exec_command(cmd, selection)
  317.  * Purpose:   Execute the given command using appropriate substitutions
  318.  ***********************************************************************************/
  319. void exec_command(char *cmd, char *sel)
  320. {
  321.  
  322.    go_dir(global.workdir);
  323.  
  324.    if (!build_command(global.cbuf, global.cbufsize, cmd, sel))
  325.    {
  326.       if (showcmd)
  327.          PostLog(global.cbuf);
  328.       IssueCommand(global.cbuf);
  329.    }
  330. }
  331.  
  332. /***********************************************************************************
  333.  * Procedure: send_rexx
  334.  * Synopsis:  send_rexx(cmd)
  335.  * Purpose:   Send the rexx command to the given port name
  336.  ***********************************************************************************/
  337. void send_rexx(char *cmd)
  338. {
  339.    char *res;
  340.    long ec;
  341.    char port[MAX_SYMBOL+1];
  342.  
  343.    go_dir(global.workdir);
  344.  
  345.    if (!build_command(global.cbuf, global.cbufsize, cmd, get_cursel()))
  346.    {
  347.       if (showcmd)
  348.          PostLog(global.cbuf);
  349.       /* Parse out the port name */
  350.       cmd = parse_keyword(global.cbuf, port);
  351.       /* Send the command off to rexx to be processed */
  352.       /* We will wait here until it is complete       */
  353.       PlaceRexxCommandDirect(NULL, port, cmd, &res, &ec);
  354.       if (res != NULL)
  355.       {
  356.          PostLog(res);
  357.          free(res);
  358.       }
  359.    }
  360.  
  361. }
  362.  
  363. /***********************************************************************************
  364.  * Procedure: log_message
  365.  * Synopsis:  log_message(msg, dorexx)
  366.  * Purpose:   Output a message to the session log
  367.  ***********************************************************************************/
  368. void log_message(char *msg, int dorexx)
  369. {
  370.    int gotmsg;
  371.  
  372.    /* set RC in case build_command() fails and doesn't say why */
  373.    if (dorexx)
  374.       global.rexxrc = TEXT_BADPARM;
  375.  
  376.    gotmsg = !build_command(global.cbuf, global.cbufsize, msg, get_cursel());
  377.    if (gotmsg)
  378.       PostLog(global.cbuf);
  379.    else
  380.       PostLog("-------------------");
  381.  
  382.    if (dorexx)
  383.    {
  384.       if (gotmsg)
  385.       {
  386.          /* undo previous default -- build_command() worked */
  387.          global.rexxrc = 0;
  388.          strcpy(global.rexxrs, global.cbuf);
  389.          global.rexxrs[global.cbufsize] = 0;
  390.       }
  391.    }
  392. }
  393.  
  394. /***********************************************************************************
  395.  * Procedure: set_workdir
  396.  * Synopsis:  set_workdir();
  397.  * Purpose:   Set the working directory based on the current directory and symbol
  398.  *            values
  399.  ***********************************************************************************/
  400. void set_workdir(void)
  401. {
  402.    if (test_dirty())
  403.    {
  404.       load_symbols();
  405.    }
  406.  
  407.    go_dir(global.homedir);
  408.    UnLock(global.workdir);
  409.    global.workdir = xlockdir(Sym_Lookup("DIR"));
  410.    go_dir(global.workdir);
  411. }
  412.  
  413. /***********************************************************************************
  414.  * Procedure: save_current
  415.  * Synopsis:  rc = save_current();
  416.  * Purpose:   Save the current file (if it has changed)
  417.  ***********************************************************************************/
  418. int save_current(int perm)
  419. {
  420.    if (test_dirty())
  421.    {
  422.       int rc;
  423.  
  424.       rc = request(0, TEXT_ASKSAVE,
  425.                    Sym_Lookup(SYM_SCRIPT), global.text[TEXT_SAVE]);
  426.  
  427.       if (!rc) return(1);
  428.  
  429.       if (rc == 2)
  430.       {
  431.          load_symbols();
  432.          if (write_file()) return(1);
  433.       }
  434.       mark_clean();
  435.    }
  436.    return(0);
  437. }
  438.  
  439. /***********************************************************************************
  440.  * Procedure: lookup_keyword
  441.  * Synopsis:  kw = lookup_keyword(&p, keystr);
  442.  * Purpose:   Lookup the keyword given and return the position of the next token
  443.  *            (If the keyword was found).  If the keyword wasn't found, -1 is returned
  444.  ***********************************************************************************/
  445. int lookup_keyword(char **bufp, char *keystr)
  446. {
  447.    int i;
  448.    char *p;
  449.    char buf[MAX_SYMBOL+1];
  450.  
  451.    p = parse_keyword(*bufp, buf);
  452.  
  453.    /* Look for the keyword in the table they provided us */
  454.    for(i = 0; *keystr; keystr += strlen(keystr)+1, i++)
  455.    {
  456.       if (!stricmp(buf, keystr))
  457.       {
  458.          /* We got it.  Return the end of the string for them */
  459.          *bufp = p;
  460.          return(i);
  461.       }
  462.    }
  463.  
  464.    /* We didn't find the keyword, so let them know */
  465.    return(-1);
  466. }
  467.  
  468. char cmdlist[] =
  469. #define KEY_TRACE     0
  470.            "TRACE\0" /* Debug the program in the current mode         */
  471. #define KEY_EDIT      1
  472.            "EDIT\0"  /* Invoke the editor on the current file         */
  473. #define KEY_EXEC      2
  474.            "EXEC\0"  /* Execute the given command                     */
  475. #define KEY_NEW       3
  476.            "NEW\0"   /* RESET, Prompt for a new file name             */
  477. #define KEY_QUIT      4
  478.            "QUIT\0"  /* Exit                                          */
  479. #define KEY_READ      5
  480.            "READ\0"  /* Read a file                                   */
  481. #define KEY_SAVE      6
  482.            "SAVE\0"  /* Save file                                     */
  483. #define KEY_FRONT     7
  484.            "FRONT\0" /* Pop Window to the front                       */
  485. #define KEY_BACK      8
  486.            "BACK\0"  /* Send Window to the back                       */
  487. #define KEY_JUMP      9
  488.            "JUMP\0"  /* Jump window to a given screen                 */
  489. #define KEY_LOG      10
  490.            "LOG\0"   /* Output a log message to the screen            */
  491. #define KEY_SCAN     11
  492.            "SCAN\0"  /* Scan the directory for a file pattern list    */
  493. #define KEY_ADDR     12
  494.            "ADDR\0"  /* Send a rexx command to a given port           */
  495. #define KEY_SET      13
  496.            "SET\0"   /* Set a symbol to a given value                 */
  497. #define KEY_CONFIG   14
  498.            "CONFIG\0"/* Change a config string                        */
  499. #define KEY_CALL     15
  500.            "CALL\0"  /* Execute a config string                       */
  501. #define KEY_SELECT   16
  502.            "SELECT\0"/* Select an element in the file list            */
  503. #define KEY_ADD      17
  504.            "ADD\0"   /* Add an element to the list                    */
  505. #define KEY_DEL      18
  506.            "DEL\0"   /* Delete the current item from the list         */
  507. #define KEY_LTOP     19
  508.            "LTOP\0"  /* Select top item in list                       */
  509. #define KEY_LBOT     20
  510.            "LBOT\0"  /* Select bottom item in list                    */
  511. #define KEY_LUP      21
  512.            "LUP\0"   /* Select next item in list                      */
  513. #define KEY_LDN      22
  514.            "LDN\0"   /* Select previous item in list                  */
  515. #define KEY_RECFG    23
  516.            "RECFG\0" /* Read in a config file                         */
  517. #define KEY_REXXI    24
  518.            "REXXI\0" /* Set REXX mode to interactive                  */
  519. ;
  520.  
  521. /***********************************************************************************
  522.  * Procedure: scan_dir
  523.  * Synopsis:  (void)scan_dir();
  524.  * Purpose:   Scan the working directory for all potential files
  525.  ***********************************************************************************/
  526. void scan_dir(char *pat)
  527. {
  528.    FILE *fp;
  529.    char buf[32];
  530.  
  531.    if (!global.filelist) return;
  532.  
  533.    if (!*pat) pat = global.text[CONFIG_FILES];
  534.  
  535.    exec_command("LIST >RAM:TEMPFILE \"%r\" LFORMAT=\"%%s%%s\"", pat);
  536.    if ((fp = fopen("RAM:TEMPFILE", "r")) != NULL)
  537.    {
  538.       while(fgets(buf, 64, fp) != NULL)
  539.       {
  540.          int len;
  541.          len = strlen(buf) - 1;  /* Get rid of the \n */
  542.          while(len && (buf[len-1] == ' ')) len--;
  543.  
  544.          buf[len] = 0; /* Make sure we null terminate it */
  545.          add_listitem(global.filelist, buf, 0, 1);
  546.       }
  547.       fclose(fp);
  548.    }
  549. }
  550.  
  551. /***********************************************************************************
  552.  * Procedure: do_command
  553.  * Synopsis:  do_command(string);
  554.  * Purpose:   Execute the command associated with a given string
  555.  ***********************************************************************************/
  556. void do_command(char *string)
  557. {
  558.    char *p;
  559.    int  cmdnum;
  560.    int  postlog;
  561.    char *callstr;
  562.    int  lclass;
  563.  
  564.    /* EDIT                - Invoke the editor on the current file         */
  565.    /* EXEC cmd            - Execute the given command                     */
  566.    /* NEW     [ file | ?] - RESET, Prompt for a new file name             */
  567.    /* QUIT                - Exit                                          */
  568.    /* READ    [ file | ?] - Read a file                                   */
  569.    /* RUN                 - Execute program in current mode               */
  570.    /* SAVE    [ file | ?] - Save file                                     */
  571.    /* FRONT               - Pop Window to the front                       */
  572.    /* BACK                - Send Window to the back                       */
  573.    /* JUMP [screen]       - Jump Window to a given screen                 */
  574.    /* LOG  [string]       - Output a long message to the screen           */
  575.  
  576.    set_workdir();
  577.    set_busy();
  578.    callstr = NULL;
  579.    postlog = 0;
  580.  
  581.    while (*string)
  582.    {
  583.       int c;
  584.  
  585.       cmdnum = lookup_keyword(&string, cmdlist);
  586.  
  587.       /* Skip over the name to the rest of the command */
  588.       p = string;
  589.  
  590.       /* Locate any trailing semi-colon so we can have multiple commands */
  591.       while(*string && (*string++ != ';'))
  592.          ;
  593.       if ((c = string[-1]) == ';')
  594.          string[-1] = 0;
  595.  
  596.  
  597.       switch(cmdnum)
  598.       {
  599.          case KEY_TRACE: /*             - Toggle the trace state */
  600.             showcmd = !showcmd;
  601.             break;
  602.          case KEY_EXEC:  /* cmd         - Execute a given command               */
  603.             InitSession();
  604.             if (save_current(0)) break;
  605.             exec_command(p, get_cursel());
  606.             break;
  607.          case KEY_NEW:   /* [ file | ?] - RESET, Prompt for a new file name     */
  608.             {
  609.                char *ext;
  610.                int  len, elen;
  611.                char buf[MAX_FILENAME+1];
  612.  
  613.                global.rexxrc = TEXT_BADPROJ; /* unless another error occurs */
  614.                if (save_current(1)) break;
  615.                if (!get_filename(p, buf, FALSE)) break;
  616.  
  617.                /* Now we need to see if the project already exists and warn them */
  618.                /* that they will be overwriting it.                              */
  619.                {
  620.                   BPTR lock;
  621.                   lock = Lock(buf, ACCESS_READ);
  622.                   if (lock != NULL)
  623.                   {
  624.                      UnLock(lock);
  625.                      if (!request(0, TEXT_ASKKILL, buf, NULL))
  626.                      {
  627.                         break;
  628.                      }
  629.                   }
  630.                }
  631.  
  632.                /* no errors, no cancellations */
  633.                global.rexxrc = 0;
  634.                commit_filename(buf);
  635.                set_gadgets(0);
  636.                reset_options();
  637.                /* indicate that a new icon will be required                */
  638.                global.oldproject = 0;
  639.                /* really trying to load a project, need to fix up ghosting */
  640.                global.unghost = 1;
  641.  
  642.                /* If they didn't put an extension on the end of it, we want to     */
  643.                /* automatically do that for them.  We should also seed the default */
  644.                /* project name for them.                                           */
  645.                p = Sym_Lookup(SYM_SCRIPT);
  646.                ext = global.text[CONFIG_EXT];
  647.                elen = strlen(ext);
  648.                len = strlen(p) - elen;
  649.  
  650.                /* If the name is shorter than the extension OR it doesn't end with */
  651.                /* the extension, then we will put the extension on for them        */
  652.                if ((len < 0) || stricmp(p+len, ext))
  653.                {
  654.                   Sym_Set("PROJECT", p, NULL);
  655.                   Sym_Set(SYM_SCRIPT, NULL, ext);
  656.                   strcpy(global.filename, Sym_Lookup(SYM_SCRIPT));
  657.                }
  658.                else
  659.                {
  660.                   p[len] = 0;
  661.                   Sym_Set("PROJECT", p, NULL);
  662.                   p[len] = *ext;
  663.                }
  664.                Sym_Set("TYPE", "Normal", NULL);
  665.                Sym_Set("CFLAGS", "-R -// -f -2.0 -d1", NULL);
  666.  
  667.                unload_symbols();
  668.                set_gadgets(1);
  669.             }
  670.             break;
  671.          case KEY_QUIT:  /*             - Exit                                  */
  672.             if (!save_current(1))
  673.                global.done = 1;
  674.             break;
  675.          case KEY_EDIT:  /*             - Invoke the editor on the current file */
  676.             global.rexxrc = TEXT_NOSEL; /* default error for interactive REXX */
  677.             if (save_current(0)) break;
  678.             {
  679.                struct stat stat_buf;
  680.                char *sel;
  681.  
  682.                /* If the file is read-only, we want to see if we can check it out  */
  683.                p = global.text[CONFIG_CO];
  684.                sel = get_cursel();
  685.                if (sel && (stat(sel, &stat_buf) >= 0))
  686.                {
  687.                   if (!(stat_buf.st_mode & S_IWRITE))
  688.                   {
  689.                      int rc;
  690.  
  691.                      /* The file exists, but is read-only.  See if they want us */
  692.                      /* to check it out for them to work on                     */
  693.                      rc = request(0, TEXT_ASKCO, sel, global.text[TEXT_CO]);
  694.                      if (rc == 0) break;  /* Don't do the edit */
  695.                      if (rc == 2)
  696.                      {
  697.                         exec_command(global.text[CONFIG_CO], sel);
  698.                      }
  699.                   }
  700.                }
  701.                /* not aborting, can't be any errors... */
  702.                global.rexxrc = 0;
  703.                /* if EDPROJ config string is filled, we can do special      */
  704.                /* handling for project file.                                */
  705.                if ((global.text[CONFIG_EDPROJ] == 0) || 
  706.                    (stricmp(sel, Sym_Lookup(SYM_SCRIPT))))
  707.                {
  708.                   exec_command(global.text[CONFIG_EDIT], sel);
  709.                   break;
  710.                }
  711.                else
  712.                {
  713.                   exec_command(global.text[CONFIG_EDPROJ], sel);
  714.                  if (sel && (stat(sel, &stat_buf) < 0))
  715.                  {
  716.                     /* Don't try to read if it doesn't exist */
  717.                     break;
  718.                  }
  719.                }
  720.             }
  721.             /* Fall through to READ to use modified project file             */
  722.             p = ""; /* READ will default to default to current project       */
  723.          case KEY_READ:  /* [ file | ?] - Read a file                        */
  724.             {
  725.                char *symcfg, *symnew;
  726.                char rbuff[200];
  727.                char buf[MAX_FILENAME+1];
  728.                struct stat stat_buf;
  729.  
  730.                global.rexxrc = TEXT_BADPROJ; /* just in case... */
  731.                if (save_current(1)) break;
  732.                if (build_command(rbuff, 200, p, get_cursel())) break;
  733.  
  734.                p = rbuff;
  735.                if (!get_filename(p, buf, FALSE)) break;
  736.                if (*buf && (stat(buf, &stat_buf) < 0))
  737.                {
  738.                   request(1, TEXT_BADFILE, buf, NULL);
  739.                   break;
  740.                }
  741.                commit_filename(buf);
  742.                set_gadgets(0);
  743.                reset_options();
  744.                if (read_file())
  745.                {
  746.                   /* For some reason we couldn't read the file,       */
  747.                   /* just reset all the options to be a null value.   */
  748.                   reset_options();
  749.                   commit_filename("");
  750.                }
  751.                else
  752.                {
  753.                   global.rexxrc = 0;     /* Everything's hunky dory now */
  754.                   /* we're really trying to do it, lock all the gadgets */
  755.                   global.unghost = 1;
  756.                }
  757.                global.oldproject = 1;
  758.  
  759.                /* now see if we need to change the config file          */
  760.                symcfg = Sym_Lookup(SYM_CONFIG);
  761.                symnew = Sym_Lookup(SYM_PROJCFG);
  762.                /* if the project doesn't specify a config file          */
  763.                if (!symnew || (symnew[0] == '\0'))
  764.                   /* revert to original default                         */
  765.                   symnew = Sym_Lookup(SYM_ORIG_CFG);
  766.                /* if configuration file name has changed                */
  767.                if (stricmp(symcfg, symnew))
  768.                {
  769.                   Sym_Set(SYM_CONFIG, symnew, 0);
  770.                   global.newscreen = 1; /* configuration redefines window */
  771.                   global.parsefail = parse_config(symnew);
  772.                   if (global.parsefail)
  773.                   {
  774.                      global.rexxrc = TEXT_BADPROJ;
  775.                      break;   /* error display in title bar             */
  776.                   }
  777.                }
  778.  
  779.                unload_symbols();
  780.                /* If we're about to redisplay the window, defer         */
  781.                /* repainting the gadgets until then                     */
  782.                if (!global.newscreen)
  783.                   set_gadgets(1);
  784.                break;
  785.             }
  786.          case KEY_SAVE:  /* [ file | ?] - Save file                     */
  787.             {
  788.                int  changed;
  789.                char *ext;
  790.                int  len, elen;
  791.                char svproj[MAX_FILENAME+1];
  792.                char newproj[MAX_FILENAME+1];
  793.  
  794.                global.rexxrc = TEXT_BADPROJ; /* in case of unnamed perils */
  795.                /* save project name in case they change it */
  796.                strncpy(svproj, Sym_Lookup(SYM_SCRIPT), MAX_FILENAME);
  797.                svproj[MAX_FILENAME] = '\0';
  798.                if (!get_filename(p, newproj, TRUE)) 
  799.                   break;
  800.                /* Now see if they have chosen a new name that already exists */
  801.                /* and warn them that they will be overwriting it.            */
  802.                changed = stricmp(svproj, newproj);
  803.                if (changed)
  804.                {
  805.                   BPTR lock;
  806.  
  807.                   lock = Lock(newproj, ACCESS_READ);
  808.                   if (lock != NULL)
  809.                   {
  810.                      UnLock(lock);
  811.                      if (!request(0, TEXT_ASKKILL, newproj, NULL))
  812.                      {
  813.                         break;
  814.                      }
  815.                   }
  816.                   /* indicate that a new icon will be required               */
  817.                   global.oldproject = 0;
  818.                }
  819.  
  820.                /* looks like they want to go through with this               */
  821.                global.rexxrc = 0;  /* didn't fail, don't lie to rexx         */
  822.  
  823.                /* If they didn't put an extension on the end of it, we want  */
  824.                /* to automatically do that for them.                         */
  825.                ext = global.text[CONFIG_EXT];
  826.                len = strlen(newproj);
  827.                elen = strlen(ext);
  828.  
  829.                /* If the name is shorter than the extension OR it doesn't end with */
  830.                /* the extension, then we will put the extension on for them        */
  831.                if ((len < elen) || stricmp(newproj+len-elen, ext))
  832.                {
  833.                   strncat(newproj, ext, MAX_FILENAME-len);
  834.                   newproj[MAX_FILENAME] = 0;
  835.                }
  836.                commit_filename(newproj);
  837.  
  838.                (void)test_dirty();
  839.                load_symbols();
  840.                if (!write_file())
  841.                {
  842.                   /* JAT's usual negative logic -- means it worked           */
  843.                   if (changed)
  844.                   {
  845.                      /* Select the old project.                              */
  846.                      handle_list(global.filelist, NULL, CLASS_SELECT, svproj, 0);
  847.                      if (global.filelist->sel != NULL) /* we got it */
  848.                      {
  849.                         /* If it was in the list, delete it                  */
  850.                         handle_list(global.filelist, NULL, CLASS_DEL, NULL, 0);
  851.                      }
  852.                      /* Now put the new project at the end or the list       */
  853.                      set_gadgets(0);
  854.                      add_listitem(global.filelist, newproj, 1, 0);
  855.                      set_gadgets(1);
  856.                   }
  857.                   /* Now the current state is saved in the new project file. */
  858.                   mark_clean();
  859.                }
  860.  
  861.                break;
  862.             }
  863.          case KEY_ADDR:  /* port cmd    - Send an arexx command to a given port */
  864.             InitSession();
  865.             if (save_current(0)) break;
  866.             send_rexx(p);
  867.             break;
  868.          case KEY_FRONT: /*             - Pop Window to the front               */
  869.             WindowToFront(global.window);
  870.             ScreenToFront(global.window->WScreen);
  871.             ActivateWindow(global.window);
  872.             break;
  873.          case KEY_BACK:  /*             - Send Window to the back               */
  874.             WindowToBack(global.window);
  875.             break;
  876.          case KEY_JUMP:  /* [screen]    - Jump Window to a given screen         */
  877.             /* This should only be done for 2.0..... */
  878.             if (AslBase)
  879.             {
  880.                char buf[MAXPUBSCREENNAME+1];
  881.                if (*p == 0)
  882.                {
  883.                   if (NextPubScreen(global.window->WScreen, buf))
  884.                      p = buf;
  885.                }
  886.                if (p)
  887.                   global.screen = LockPubScreen(p);
  888.                else
  889.                   global.screen = 0;
  890.                /* force main event loop to close & reopen the window */
  891.                global.newscreen = 1;
  892.                break;
  893.             }
  894.             request(1, TEXT_BADCMD, "--- JUMP Dos 1.3---", NULL);
  895.             break;
  896.          case KEY_RECFG:
  897.             if (save_current(0) == 0) /* didn't change their mind? */
  898.             {
  899.                char cfname[MAX_FILENAME+1];
  900.                char *cfp = p;
  901.  
  902.                if (*cfp == 0)
  903.                   if (get_work_filename(cfname, CONFIG_CFGFPAT))
  904.                      cfp = cfname;
  905.  
  906.                if (*cfp != 0) /* got a name from somewhere */
  907.                {
  908.                   Sym_Set(SYM_CONFIG, cfp, 0);
  909.                   global.newscreen = 1; /* configuration redefines window */
  910.                   set_gadgets(0);
  911.                   load_symbols();
  912.                   global.parsefail = parse_config(cfp);
  913.                   if (!global.parsefail)
  914.                   {
  915.                      unload_symbols();
  916.                      Sym_Set(SYM_PROJCFG, cfp, 0);
  917.                      global.dirtysym = DOSTRUE;
  918.                   }
  919.                }
  920.             }
  921.             break;
  922.          case KEY_LOG:   /* message     - Output message to the log             */
  923.             log_message("\n---------------------------", 0);
  924.             log_message(p, global.rexxmsgs);
  925.             postlog = 1;
  926.             break;
  927.          case KEY_SCAN:  /*             - Scan for a list of files              */
  928.             set_gadgets(0);
  929.             scan_dir(p);
  930.             set_gadgets(1);
  931.             break;
  932.          case KEY_SET:
  933.             {
  934.                char buf[MAX_SYMBOL+1];
  935.  
  936.                p = parse_keyword(p, buf);
  937.                if (buf[0] == 0)
  938.                {
  939.                   request(1, TEXT_BADPARM, NULL, NULL);
  940.                   break;                  
  941.                }
  942.                Sym_Set(buf, p, NULL);
  943.                if (buf[0] != '_')
  944.                   global.dirtysym = DOSTRUE; /* to flag save_current()  */
  945.             }
  946.             break;
  947.          case KEY_CONFIG:
  948.             {
  949.                char buf[MAX_SYMBOL+1];
  950.  
  951.                p = parse_keyword(p, buf);
  952.  
  953.                cmdnum = atoi(buf);
  954.                if ((cmdnum > 0) && (cmdnum <= NUM_CONFIG))
  955.                {
  956.                   if (global.text[CONFIG_BASE-1+cmdnum])
  957.                      free(global.text[CONFIG_BASE-1+cmdnum]);
  958.                   global.text[CONFIG_BASE-1+cmdnum] = strdup(p);
  959.                }
  960.                else
  961.                   request(1, TEXT_BADPARM, NULL, NULL);
  962.             }
  963.             break;
  964.          case KEY_SELECT:
  965.             /* Select the given name. */
  966.             handle_list(global.filelist, NULL, CLASS_SELECT, p, 0);
  967.             if (global.filelist->sel == NULL) /* we didn't select anything */
  968.                if (*p != '\0') /* and we weren't just trying to deselect   */
  969.                   request(1, TEXT_SELFAIL, p, NULL);
  970.             break;
  971.          case KEY_LTOP:
  972.             lclass = CLASS_LTOP;
  973.             goto listmove;
  974.          case KEY_LBOT:
  975.             lclass = CLASS_LBOT;
  976.             goto listmove;
  977.          case KEY_LUP:
  978.             lclass = CLASS_LUP;
  979.             goto listmove;
  980.          case KEY_LDN:
  981.             lclass = CLASS_LDN;
  982.       listmove:
  983.             handle_list(global.filelist, NULL, lclass, p, 0);
  984.             if (global.inrexx) /* don't nag but do rexx error codes        */ 
  985.                if (global.filelist->sel == NULL) /* didn't select anything */
  986.                   request(1, TEXT_SELFAIL, p, NULL);
  987.             break;
  988.          case KEY_ADD:
  989.             /* add an item to the file list, can specify name with command */
  990.             handle_list(global.filelist, NULL, CLASS_ADD, p, 0);
  991.             break;
  992.          case KEY_DEL:
  993.             /* Delete the current selection from the file list             */
  994.             if (global.inrexx) /* error msg helpful in rexx, else irritating */
  995.             { 
  996.                if (global.filelist->sel == NULL) /* can't delete nothing   */
  997.                {
  998.                   request(1, TEXT_NOSEL, NULL, NULL);
  999.                   break; /* so don't call delete routine                   */
  1000.                }
  1001.                if (*p != '\0') /* DEl doesn't take parameters              */
  1002.                {
  1003.                   request(1, TEXT_BADPARM, NULL, NULL);
  1004.                   break; /* so don't call delete routine                   */
  1005.                }
  1006.             }
  1007.             handle_list(global.filelist, NULL, CLASS_DEL, p, 0);
  1008.             break;
  1009.          case KEY_REXXI:
  1010.             /* set REXX interactive mode on or off                         */
  1011.             if (!stricmp(p, "on"))
  1012.             {
  1013.                /* Interactive, allows requesters */
  1014.                global.rexxinter = 1;
  1015.                Sym_Set(SYM_REXXINTER, "ON", NULL);
  1016.             }
  1017.             else
  1018.             {
  1019.                if (!stricmp(p, "off"))
  1020.                {
  1021.                   /* set REXX mode to fail instead of displaying requesters */
  1022.                   global.rexxinter = 0;
  1023.                   Sym_Set(SYM_REXXINTER, "OFF", NULL);
  1024.                }
  1025.                else 
  1026.                {
  1027.                   request(1, TEXT_BADRMODE, p, NULL);
  1028.                }
  1029.             }
  1030.             break;
  1031.          case KEY_CALL:
  1032.             if (callstr == NULL)
  1033.             {
  1034.                char buf[MAX_SYMBOL+1];
  1035.  
  1036.                p = parse_keyword(p, buf);
  1037.  
  1038.                cmdnum = atoi(buf);
  1039.                if ((cmdnum > 0)           &&
  1040.                    (cmdnum <= NUM_SUBRTN) &&
  1041.                    ((p = global.text[cmdnum+SUBRTN_BASE-1]) != NULL) &&
  1042.                    *p)
  1043.                {
  1044.                   string[-1] = c;
  1045.                   callstr = string;
  1046.                   string = p;
  1047.                   continue;
  1048.                }
  1049.                break;
  1050.             }
  1051.          default:
  1052.             /* We have an invalid option, ignore the command and let them know  */
  1053.             /* about the problem with the option.                               */
  1054.             request(1, TEXT_BADCMD, p, NULL);
  1055.             /* We also don't want to process any more commands...               */
  1056.             string[-1] = c;
  1057.             goto doneall;
  1058.       }
  1059.       string[-1] = c;
  1060.       if ((*string == '\0') && (callstr != NULL))
  1061.       {
  1062.          string = callstr;
  1063.          callstr = NULL;
  1064.       }
  1065.    }
  1066.  
  1067. doneall:
  1068.    if (postlog)
  1069.    {
  1070.       log_message("---------------------------", 0);
  1071.       if (!global.inrexx)
  1072.          ActivateWindow(global.window);
  1073.    }
  1074.    set_idle();
  1075. }
  1076.  
  1077. /***********************************************************************************
  1078.  * Procedure: reset_options
  1079.  * Synopsis:  reset_options()
  1080.  * Purpose:   Reset all the options to the default values
  1081.  ***********************************************************************************/
  1082. void reset_options(void)
  1083. {
  1084. #define object_list  ((struct G_LIST *)object)
  1085. #define object_str   ((struct G_STRING *)object)
  1086. #define object_cycle ((struct G_CYCLE *)object)
  1087.    struct G_OBJECT *object;
  1088.    char *p;
  1089.  
  1090.    /* First make sure that all the right symbols are in the symbol table in the */
  1091.    /* correct order.  Since the symbol table routines guarentee that it will    */
  1092.    /* keep the order of the entries once they are there, we only need to touch  */
  1093.    /* the order once to keep it correct for the dmakefile.                      */
  1094.    Sym_Clear();
  1095.  
  1096.    p = "PROJECT\0"
  1097.        "DIR\0"
  1098.        "SRCS\0"
  1099.        "HDRS\0"
  1100.        "EXTRAS\0"
  1101.        "PDEFAULT\0"
  1102.        "EXEDIR\0"
  1103.        "OD\0"
  1104.        "PRECOMP\0"
  1105.        "TYPE\0"
  1106.        "RUN\0"
  1107.        "CLIARGS\0"
  1108.        "CFLAGS\0";
  1109.  
  1110.    while(*p)
  1111.    {
  1112.       Sym_Set(p, NULL, "");
  1113.       p += strlen(p)+1;
  1114.    }
  1115.  
  1116.    object = global.objects;
  1117.  
  1118.    while(object != NULL)
  1119.    {
  1120.       switch(object->class)
  1121.       {
  1122.          case CLASS_STRING:
  1123.             object_str->buf[0] = 0;
  1124.             break;
  1125.          case CLASS_CYCLE:
  1126.             {
  1127.                struct G_VALUE *val;
  1128.  
  1129.                val = object_cycle->curval = object_cycle->values;
  1130.                while(val != NULL)
  1131.                {
  1132.                   if (val->string)
  1133.                      val->string->buf[0] = 0;
  1134.                   val = val->next;
  1135.                }
  1136.             }
  1137.             break;
  1138.          case CLASS_LIST:
  1139.             {
  1140.                struct G_ENTRY *ent;
  1141.                ent = object_list->first;
  1142.                object_list->first = object_list->top = NULL;
  1143.                object_list->sel = NULL;
  1144.                object_list->maxent = 0;
  1145.  
  1146.                while(ent != NULL)
  1147.                {
  1148.                   struct G_ENTRY *nextent;
  1149.  
  1150.                   nextent = (struct G_ENTRY *)ent->base.next;
  1151.                   free_mem(ent, sizeof(struct G_ENTRY));
  1152.                   ent = nextent;
  1153.                }
  1154.             }
  1155.             break;
  1156.          case CLASS_BUTTON:
  1157.             break;
  1158.          default:
  1159.             object->state = 0;
  1160.             break;
  1161.       }
  1162.       object = object->next;
  1163.    }
  1164. #undef object_list
  1165. #undef object_str
  1166. #undef object_cycle
  1167.    mark_clean();
  1168.  
  1169.    UnLock(global.workdir);
  1170.    global.workdir = 0;
  1171. }
  1172.  
  1173. /***********************************************************************************
  1174.  * Procedure: unload_symbols
  1175.  * Synopsis:  unload_symbols();
  1176.  * Purpose:   Unload the symbols into the objects
  1177.  ***********************************************************************************/
  1178. void unload_symbols()
  1179. {
  1180.    struct G_OBJECT *object, *savelist;
  1181.    char *p;
  1182.  
  1183. #define object_list  ((struct G_LIST   *)object)
  1184. #define object_str   ((struct G_STRING *)object)
  1185. #define object_check ((struct G_CHECK  *)object)
  1186. #define object_cycle ((struct G_CYCLE  *)object)
  1187.  
  1188.    for(object = global.objects; object != NULL; object = object->next)
  1189.    {
  1190.       switch(object->class)
  1191.       {
  1192.          case CLASS_STRING:
  1193.             strcpy(object_str->buf, Sym_Lookup(object_str->option));
  1194.             break;
  1195.          case CLASS_CYCLE:
  1196.             {
  1197.                char buf[MAX_SYMBOL+1];
  1198.                struct G_VALUE *val;
  1199.  
  1200.                for(val = object_cycle->values;
  1201.                    val != NULL;
  1202.                    val = (struct G_VALUE *)val->next)
  1203.                {
  1204.                   char *arg;
  1205.                   /* Gather the current name into a buffer */
  1206.                   p = parse_keyword(val->option, buf);
  1207.                   arg = Sym_Lookup(buf);
  1208.                   if (val->string)
  1209.                   {
  1210.                      /* If the next character is a % sign, we have an exact */
  1211.                      /* match that we can just fill in.   Otherwise it is   */
  1212.                      /* the name of a string that we should lookup for the  */
  1213.                      /* final symbol to fill it in with                     */
  1214.                      if (*p != '%')
  1215.                      {
  1216.                         /* Parse out the next token - this is the secondary */
  1217.                         /* Mode.  This must match the value of the primary  */
  1218.                         /* option if we are to take it                      */
  1219.                         parse_keyword(p, buf);
  1220.                         if (strcmp(buf, arg)) continue;  /* Sorry, try the next one */
  1221.  
  1222.                         /* We have a match, look up the substitution value  */
  1223.                         /* for the string buffer                            */
  1224.                         arg = Sym_Lookup(buf);
  1225.                      }
  1226.                      /* Copy the string into the object cycle buffer */
  1227.                      strcpy(val->string->buf, arg);
  1228.                      object_cycle->curval = val;
  1229.                      break;
  1230.                   }
  1231.                   else
  1232.                   {
  1233.                      /* Not a string entry.  It must match exactly */
  1234.                      if (!strcmp(p, arg))
  1235.                      {
  1236.                         object_cycle->curval = val;
  1237.                         break;
  1238.                      }
  1239.                   }
  1240.                }
  1241.             }
  1242.             break;
  1243.          case CLASS_LIST:
  1244.             if (!stricmp(object_list->option, "Files"))
  1245.             {
  1246.                savelist = object;
  1247.                /* Populate it with all the strings from the list */
  1248.                add_list(object_list, Sym_Lookup("SRCS"),      0);
  1249.                add_list(object_list, Sym_Lookup("HDRS"),      0);
  1250.                add_list(object_list, Sym_Lookup("EXTRAS"),    0);
  1251.                add_list(object_list, Sym_Lookup(SYM_SCRIPT),  1);
  1252.             }
  1253.             else
  1254.             {
  1255.                add_list(object_list, Sym_Lookup(object_list->option), 0);
  1256.             }
  1257.             break;
  1258.       }
  1259.    }
  1260.  
  1261.    mark_clean();
  1262. #undef object_check
  1263. #undef object_list
  1264. #undef object_str
  1265. #undef object_cycle
  1266. }
  1267.  
  1268. /***********************************************************************************
  1269.  * Procedure: load_symbols
  1270.  * Synopsis:  load_symbols();
  1271.  * Purpose:   load the symbols from the current objects
  1272.  ***********************************************************************************/
  1273. void load_symbols()
  1274. {
  1275.    struct G_OBJECT *object;
  1276.    char *p, *arg;
  1277.  
  1278. #define object_list  ((struct G_LIST   *)object)
  1279. #define object_str   ((struct G_STRING *)object)
  1280. #define object_check ((struct G_CHECK  *)object)
  1281. #define object_cycle ((struct G_CYCLE  *)object)
  1282.  
  1283.    for(object = global.objects; object != NULL; object = object->next)
  1284.    {
  1285.       /* Don't even bother with this object if it hasn't changed */
  1286.       if (!object->state & DIRTY_BIT) continue;
  1287.  
  1288.       switch(object->class)
  1289.       {
  1290.          case CLASS_STRING:
  1291.             Sym_Set(object_str->option, object_str->buf, NULL);
  1292.             break;
  1293.  
  1294.          case CLASS_CYCLE:
  1295.             {
  1296.                struct G_VALUE *val;
  1297.                char buf[MAX_SYMBOL+1];
  1298.                char sec[MAX_SYMBOL+1];
  1299.  
  1300.                val = object_cycle->curval;
  1301.                p = parse_keyword(val->option, buf);
  1302.  
  1303.                if (val->string)
  1304.                {
  1305.                   /* If the next token is a '%', we just use the string buffer */
  1306.                   /* as the result value                                       */
  1307.                   if (*p == '%')
  1308.                   {
  1309.                      p = val->string->buf;
  1310.                   }
  1311.                   else
  1312.                   {
  1313.                      /* Special case of a cascade definition */
  1314.                      /* We need to set the primary definition to the secondary */
  1315.                      /* name and the secondary definition to the string        */
  1316.                      parse_keyword(p, sec);
  1317.                      Sym_Set(sec, val->string->buf, NULL);
  1318.                      p = sec;
  1319.                   }
  1320.                }
  1321.                Sym_Set(buf, p, NULL);
  1322.  
  1323.                /* Handle the one special case that we know about:  */
  1324.                /*   TYPE <whatever> causes us to read in a new script */
  1325.                if (!strcmp(buf, "TYPE"))
  1326.                   read_script();
  1327.             }
  1328.             break;
  1329.  
  1330.          case CLASS_LIST:
  1331.             {
  1332.                int firsttime;
  1333.                struct G_ENTRY *ent;
  1334.                Sym_Set("EXTRAS", "", NULL);
  1335.                Sym_Set("SRCS",   "", NULL);
  1336.                Sym_Set("HDRS",   "", NULL);
  1337.                /* Files                                                                           */
  1338.                /*  - List of C and O files.  Always relative to the current directory             */
  1339.                /*  - Generates the SRCS and HDRS directories by splitting out based on extension. */
  1340.                /*  - Things ending in .C or .A go into SRCS                                       */
  1341.                /*  - Things ending in .H go into HDRS                                             */
  1342.                /*  - All others go into FILES_ext where ext is the extension of the file          */
  1343.                for(firsttime = 1, ent = object_list->first; ent != NULL;
  1344.                    ent = (struct G_ENTRY *)ent->base.next, firsttime = 0)
  1345.                {
  1346.                   arg = "EXTRAS";
  1347.                   p = strrchr(ent->buf, '.');
  1348.                   if (p != NULL)
  1349.                   {
  1350.                      if ((!stricmp(p, ".c")) || (!stricmp(p, ".a"))) arg = "SRCS";
  1351.                      else if (!stricmp(p, ".h"))
  1352.                      {
  1353.                         char *t;
  1354.                         t = strrchr(ent->buf, '/');
  1355.                         if (t == NULL) t = strrchr(ent->buf, ':');
  1356.                         if (t == NULL) t = ent->buf;
  1357.                         arg = "HDRS";
  1358.                         if (p > t)
  1359.                         {
  1360.                            *p = 0;
  1361.                            if (!stricmp(t, Sym_Lookup("PROJECT")))
  1362.                            {
  1363.                               *p = '.';
  1364.                               Sym_Set("PDEFAULT", ent->buf, NULL);
  1365.                            }
  1366.                            *p = '.';
  1367.                         }
  1368.                      }
  1369.                   }
  1370.                   /* Make sure that we don't put the script in there more than */
  1371.                   /* once......  It is already present as the DMAKEFILE one    */
  1372.                   if (!(ent->base.state & STATE_MASK))
  1373.                   {
  1374.                      if (stricmp(object_list->option, "Files"))
  1375.                         arg = object_list->option;
  1376.  
  1377.                      if (*Sym_Lookup(arg)) Sym_Set(arg, NULL, " ");
  1378.  
  1379.                      /* If the filename has spaces, we need to put it in quotes */
  1380.                      if (strchr(ent->buf, ' '))
  1381.                      {
  1382.                         Sym_Set(arg, NULL, "\'");
  1383.                         Sym_Set(arg, NULL, ent->buf);
  1384.                         Sym_Set(arg, NULL, "\'");
  1385.                      }
  1386.                      else
  1387.                      {
  1388.                         Sym_Set(arg, NULL, ent->buf);
  1389.                      }
  1390.                   }
  1391.                }
  1392.             }
  1393.             break;
  1394.       }
  1395.    }
  1396.  
  1397. #undef object_check
  1398. #undef object_list
  1399. #undef object_str
  1400. #undef object_cycle
  1401.  
  1402.    /* A couple of symbols MUST be a directory with the appropriate */
  1403.    /* Directory separator character on the end of it               */
  1404.    /*   DIR                                                        */
  1405.    /*   EXEDIR                                                     */
  1406.    /*   OD                                                         */
  1407.    p = "DIR\0"
  1408.        "EXEDIR\0"
  1409.        "OD\0";
  1410.    for (;*p; p += strlen(p)+1)
  1411.    {
  1412.       char *val;
  1413.       int len;
  1414.  
  1415.       val = Sym_Lookup(p);
  1416.  
  1417.       len = strlen(val);
  1418.       if (len && (val[len-1] != ':') && (val[len-1] != '/'))
  1419.          Sym_Set(p, NULL, "/");
  1420.    }
  1421. }
  1422.  
  1423. /***********************************************************************************
  1424.  * Procedure: add_list
  1425.  * Synopsis:  add_list(list, name)
  1426.  * Purpose:   Add all the filenames in the named symbol table into the list object
  1427.  ***********************************************************************************/
  1428. void add_list(struct G_LIST *list,
  1429.               char *name,
  1430.               int private)
  1431. {
  1432.    char buf[MAX_STRING+1];
  1433.    int pos, c, state;
  1434.  
  1435.    pos = 0;
  1436.    state = 0;
  1437.  
  1438.    do
  1439.    {
  1440.       c = *name++;
  1441.       if (((state == 1) && (c == '\'')) || (pos && (c == ' ' || c == 0)))
  1442.       {
  1443.          buf[pos] = 0;
  1444.          add_listitem(list, buf, private, 0);
  1445.          state = 0;
  1446.          pos = 0;
  1447.       }
  1448.       else
  1449.       {
  1450.          if (c == '\'')     state = 1;
  1451.          else if (state || (c != ' ')) buf[pos++] = c;
  1452.          if (pos == MAX_STRING) pos = MAX_STRING-1;
  1453.       }
  1454.    } while(c);
  1455. }
  1456.  
  1457. /***********************************************************************************
  1458.  * Procedure: add_listitem
  1459.  * Synopsis:  add_listitem(list, name, private, dirty)
  1460.  * Purpose:   Add the given name into the current list
  1461.  ***********************************************************************************/
  1462. void add_listitem(struct G_LIST *list, char *name, int private, int dirty)
  1463. {
  1464.    struct G_ENTRY *ent, *prevent;
  1465.  
  1466.    ent = get_mem(sizeof(struct G_ENTRY));
  1467.    if (ent == NULL) return;
  1468.  
  1469.    strcpy(ent->buf, name);
  1470.    ent->base.state = private;
  1471.    if (dirty)
  1472.       list->base.state |= DIRTY_BIT;
  1473.  
  1474.    /* Figure out where to add the name */
  1475.  
  1476.    /* link the new name into the list */
  1477.    if (list->first == NULL)
  1478.    {
  1479.       list->top = list->first = ent;
  1480.    }
  1481.    else
  1482.    {
  1483.       int i;
  1484.       for (i = 0, prevent = list->first; prevent->base.next;
  1485.            prevent = (struct G_ENTRY *)prevent->base.next, i++)
  1486.       {
  1487.          /* Make sure it isn't already in the list */
  1488.          if (!stricmp(prevent->buf, name))
  1489.          {
  1490.             free_mem(ent, sizeof(struct G_ENTRY));
  1491.             return;
  1492.          }
  1493.       }
  1494.       prevent->base.next = (struct G_OBJECT *)ent;
  1495.       ent->base.prev = (struct G_OBJECT *)prevent;
  1496.    }
  1497. }